package com.jcode.netty.client;

import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.net.SocketAddress;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jcode.netty.core.NetEvent;
import com.jcode.netty.core.NetEventType;
import com.jcode.netty.protocol.Packet;
import com.jcode.netty.util.RemotingHelper;

/**
 * 
 *
 * @Author dreajay
 * @DateTime 2016年10月15日 上午11:12:27
 *
 */
public class ClientHandler extends ChannelDuplexHandler {
	private static Logger log = LoggerFactory.getLogger(ClientHandler.class);

	NettyClient client;

	public ClientHandler(NettyClient client) {
		this.client = client;
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
		client.processMessageReceived(ctx, (Packet) msg);
	}

	@Override
	public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) throws Exception {
		final String local = localAddress == null ? "UNKNOW" : localAddress.toString();
		final String remote = remoteAddress == null ? "UNKNOW" : remoteAddress.toString();
		log.info("NETTY CLIENT PIPELINE: CONNECT  {} => {}", local, remote);
		super.connect(ctx, remoteAddress, localAddress, promise);
		client.fireNetEvent(new NetEvent(NetEventType.CONNECT, remoteAddress.toString(), ctx.channel()));
	}

	@Override
	public void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
		final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
		log.info("NETTY CLIENT PIPELINE: DISCONNECT {}", remoteAddress);
		client.closeChannel(ctx.channel());
		super.disconnect(ctx, promise);
		client.fireNetEvent(new NetEvent(NetEventType.CLOSE, remoteAddress, ctx.channel()));
	}

	@Override
	public void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
		final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
		log.info("NETTY CLIENT PIPELINE: CLOSE {}", remoteAddress);
		client.closeChannel(ctx.channel());
		super.close(ctx, promise);
		client.fireNetEvent(new NetEvent(NetEventType.CLOSE, remoteAddress, ctx.channel()));
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
		log.warn("NETTY SERVER PIPELINE: exceptionCaught {} {}", remoteAddress, cause.getClass().getCanonicalName(), cause);
		client.closeChannel(ctx.channel());
		client.fireNetEvent(new NetEvent(NetEventType.EXCEPTION, remoteAddress, ctx.channel()));

	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent evnet = (IdleStateEvent) evt;
			// READER_IDLE \ WRITER_IDLE \ ALL_IDLE
			if (evnet.state().equals(IdleState.ALL_IDLE)) {
				final String remoteAddress = RemotingHelper.parseChannelRemoteAddr(ctx.channel());
				log.error("NETTY SERVER PIPELINE: IDLE exception [{}]", remoteAddress);
				client.closeChannel(ctx.channel());
				client.fireNetEvent(new NetEvent(NetEventType.ALL_IDLE, remoteAddress, ctx.channel()));
			}
		}
		ctx.fireUserEventTriggered(evt);
	}

}
